/*******************************************************************************
 * Copyright (c) 2006 CEA List.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     CEA List - initial API and implementation
 *******************************************************************************/
package com.cea.papyrus.core.pseudoelement;

import java.util.List;

import org.eclipse.gef.requests.CreationFactory;
import org.eclipse.uml2.uml.Element;

import com.cea.papyrus.core.extensionpoints.palette.Button;
import com.cea.papyrus.core.helper.ModelerHelper;
import com.cea.papyrus.core.utils.Debug;
import com.cea.papyrus.core.utils.IFilter;
import com.cea.papyrus.diagraminterchange2.di2.Diagram;
import com.cea.papyrus.diagraminterchange2.di2.GraphElement;
import com.cea.papyrus.diagraminterchange2.di2.Uml1SemanticModelBridge;

/**
 * Utility class.
 */
public class UMLElementFactory extends EnhancedType implements CreationFactory {

	/** debug channel */
	protected final static int channel = 23;
	
	/**
	 * 
	 */
	private final Class clazz;
	
	/**
	 * 
	 */
	private final String kind;
	
	/**
	 * 
	 */
	private final List<String> stereotypes;
	
	/**
	 * 
	 */
	private final String presentation;
	
	/**
	 * 
	 */
	private final Button extensionButton;
	
	/**
	 * Constructor.
	 * 
	 * @param presentation 
	 * @param kind 
	 * @param clazz 
	 * @param stereotypes 
	 */
	public UMLElementFactory(Class clazz, String kind, List<String> stereotypes, String presentation) {
		this.clazz = clazz;
		this.kind = kind;
		this.stereotypes = stereotypes;
		this.presentation = presentation;
		
		this.extensionButton = null;
	}
	
	/**
	 * Constructor required to be able to use filter
	 * with lazy acces.
	 * 
	 * @param button 
	 */
	public UMLElementFactory(Button button) {
		this.clazz = button.getUMLType();
		this.kind = button.getUMLTypeKind();
		this.stereotypes = button.getUMLStereotypeNames();
		this.presentation = button.getPresentation();
		
		extensionButton = button;
	}
	
	/**
	 * 
	 * 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean canExecute(GraphElement source) {
		
		if (source == null) {
			return true;
		}
	
		Element sourceElt = null;
		if (source.getSemanticModel() == null) {
			// Maybe, the source is a Diagram ?...
			// if object to create is a node,
			// test Diagram parent instead
			if (extensionButton.getGraphType().equals("NODE") && (source instanceof Diagram)) {
				Uml1SemanticModelBridge umlBridge = (Uml1SemanticModelBridge) ((Diagram) source).getOwner();
				sourceElt = umlBridge.getElement();
			} // else element source is null			
		} else {
			Uml1SemanticModelBridge umlBridge = (Uml1SemanticModelBridge) source.getSemanticModel();	
			sourceElt = umlBridge.getElement();
		}
	
		if (sourceElt == null) {
			// no uml element attached
			// --> no test to do
			return true;
		}
		
		return testFilters(sourceElt, null);
	}
	
	/**
	 * 
	 * 
	 * @param target 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean canExecute(GraphElement source, GraphElement target) {

		if (	(source == null) 
				|| (source.getSemanticModel() == null)
				|| (target == null)
				|| (target.getSemanticModel() == null)) {
			return true;
		}
		
		Uml1SemanticModelBridge umlBridge;
		// Get source
		umlBridge         = (Uml1SemanticModelBridge) source.getSemanticModel();		
		Element sourceElt = umlBridge.getElement();
		// Get target
		umlBridge         = (Uml1SemanticModelBridge) target.getSemanticModel();		
		Element targetElt = umlBridge.getElement();
		
		if ((sourceElt == null) || (targetElt == null)) {
			// no uml element attached
			// --> no test to do
			return true;
		}
		
		return testFilters(sourceElt, targetElt);
	}
	
	/**
	 * 
	 * 
	 * @param target 
	 * @param source 
	 * 
	 * @return 
	 */
	public boolean testFilters(Object source, Object target) {
		boolean isAllowed = true;
		
		IFilter sourceFilter = getParentFilter();
		IFilter targetFilter = getTargetFilter();
		
		// Test source/parent first
		if (sourceFilter != null) {
			isAllowed = sourceFilter.isAllowed(source);
		}
		
		// If test failed or target == null --> stop here
		if ((!isAllowed) || (target == null) || (targetFilter == null)) {
			return isAllowed;
		}
		
		// Test target
		isAllowed = targetFilter.isAllowed(target);		
		
		return isAllowed;
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	private IFilter getParentFilter() {
		if (extensionButton == null) {
			Debug.error(this, "UMLElementFactory::getParentFilter() : bad constructor used, extension button is null.", channel);
			return null;
		}
			
		return extensionButton.getParentFilter();
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	private IFilter getTargetFilter() {
		if (extensionButton == null) {
			Debug.error(this, "UMLElementFactory::getTargetFilter() : bad constructor used, extension button is null.", channel);
			return null;
		}
		
		return extensionButton.getTargetFilter(); 
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public Class getObjectType() {
		return null;
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public Object getNewObject() {
		return this;
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public Class getClazz() {
		return clazz;
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public String getKind() {
		return kind;
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public String getPresentation() {
		if (presentation==null)
		{return ModelerHelper.DEFAULT_PRESENTATION;}
		
		if (presentation.equals("TEXT")) {
			return ModelerHelper.TEXT_STEREOTYPE_PRESENTATION;		
		} else if (presentation.equals("TEXT_ICON")) {
			return ModelerHelper.TEXT_ICON_STEREOTYPE_PRESENTATION;
		} else if (presentation.equals("ICON")) {
			return ModelerHelper.ICON_STEREOTYPE_PRESENTATION;
		} else if (presentation.equals("SHAPE")) {
			return ModelerHelper.IMAGE_STEREOTYPE_PRESENTATION;
		} else {
			return ModelerHelper.DEFAULT_PRESENTATION;
		}
	}
	
	/**
	 * 
	 * 
	 * @return 
	 */
	public List<String> getStereotypes() {
		return stereotypes;
	}
}